from typing import List, Tuple, Optional

from mg_app_framework import get_logger
from tornado.httputil import HTTPFile

from common_bind_service.constant.header_constant import HeaderConstant
from common_bind_service.context_utils.context_utils import ContextUtils
from common_bind_service.dao.container_mark_config_dao import ContainerMarkConfigDao
from common_bind_service.models.container_config import ContainerMarkConfig
from common_bind_service.models.serializer.response import Response
from common_bind_service.pkg.excel.excel_operate import ExcelOperate


class ContainerMarkConfigService(object):

    def __init__(self):
        self.container_mark_config_dao = ContainerMarkConfigDao()

    async def get_all(self) -> Response:
        config_list = await self.container_mark_config_dao.get_all()
        config_list = [item.dict() for item in config_list]
        ret_data = {
            'data_header': HeaderConstant.container_mark_config_header,
            'data': config_list
        }

        return Response.success(ret_data)

    async def check_container_mark(self, mark: str) -> Tuple[Optional[ContainerMarkConfig], str]:
        """校验容器码"""
        config_list = ContextUtils.get_container_mark_config()
        if not config_list:
            return None, '配置为空, 请先导入码值规则'
        for config in config_list:
            if mark.startswith(config.prefix):
                # 解析剩余的流水号
                num_str = mark[len(config.prefix):]
                if len(num_str) != config.serial_len:
                    return None, '托盘码值流水号错误'
                try:
                    num = int(num_str)
                    if not (config.start <= num <= config.end):
                        return None, '码值流水号错误'
                    else:
                        return config, ''
                except Exception:
                    return None, '码值流水号错误'
        return None, '码值错误, 解析失败'




    async def full_import_data(self, file: HTTPFile) -> Response:
        filename, file_data = file.get('filename'), file.get('body')
        filename: str
        get_logger().info(f'full_import_data file {filename}')

        parse_header, parse_result_list = ExcelOperate.parse_import(HeaderConstant.container_mark_config_header,
                                                                                file_data)

        expected_cn_header = [i['name'] for i in HeaderConstant.container_mark_config_header]

        if parse_header != expected_cn_header:
            return Response.fail('导入表头有误')

        to_check_codes = {}
        insert_list = []
        for row, parse_item in enumerate(parse_result_list, 2):
            prefix = parse_item.get('prefix')
            if not prefix:
                return Response.fail(f'第{row}行前缀不能为空')

            try:
                parse_item['start'] = int(parse_item['start'])
                parse_item['serial_len'] = int(parse_item['serial_len'])
                parse_item['end'] = int(parse_item['end'])
                parse_item['max_count'] = int(parse_item['max_count'])
                parse_item['remark'] = parse_item.get('remark') or ''

            except Exception:
                return Response.fail(f'第{row}行存异常值')

            if prefix in to_check_codes:
                return Response.fail(f'第{row}行前缀与第{to_check_codes[prefix]}行重复')

            to_check_codes[prefix] = row

            insert_list.append(
                ContainerMarkConfig(**parse_item)
            )

        # 检测这些存在这些编码的配方
        if not to_check_codes:
            return Response.fail('导入数据不能为空')

        await self.container_mark_config_dao.delete_many_by_query({})
        await self.container_mark_config_dao.insert_many(insert_list)
        ContextUtils.set_container_mark_config(insert_list)
        get_logger().info('全量导入容器码值规则配置成功')
        return Response.success()